##xxxxxxxxxxxxxxxxxxxxxxxxx C++ CMake 跨平台通用设置, 需要放在 project(xxx) 调用后面
option(MY_ENABLE_CUDA_DEBUG "Enable cuda-gdb for builds" OFF)

##xxxxxxxxxxxxxxxxxxx toolchain configs; IDE 设置
# 让 generator 生成 clangd 需要的 build/compile_commands.json
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

##xxxxxxxxxxxxxxxxxxx c++, cuda 语言设置
# option(BUILD_SHARED_LIBS "Build shared libraries" ON)
set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries")
##
find_package(CUDAToolkit REQUIRED)
##
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_STANDARD 17) # C++ 标准
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# set(CMAKE_CXX_EXTENSIONS OFF)
##
set(CMAKE_CUDA_STANDARD 17) # cuda c++17
set(CMAKE_CUDA_STANDARD_REQUIRED ON)

##=============== cuda architectures
# set(CMAKE_CUDA_ARCHITECTURES 75 80 86 87 89 90 100 110 120) # nvidia cuda sample 的设置
# set(CMAKE_CUDA_ARCHITECTURES 86 120)
set(CMAKE_CUDA_ARCHITECTURES 86)
# set(CMAKE_CUDA_ARCHITECTURES native)
message(STATUS "[cuda] CMAKE_CUDA_ARCHITECTURES => ${CMAKE_CUDA_ARCHITECTURES}")
##=============== cuda debug 设置
if(MY_ENABLE_CUDA_DEBUG)
    message(STATUS "[cuda] cuda debug mode")
    set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G")        # enable cuda-gdb (可能大大降低某些 targets 的性能)
else()
    message(STATUS "[cuda] cuda release mode")
    set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif()

##xxxxxxxxxxxxxxxxxxx linux 二进制 属性
# set(CMAKE_SKIP_RPATH TRUE) # 禁用自动RPATH
# set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
set(CMAKE_INSTALL_RPATH "$ORIGIN")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH OFF)

##xxxxxxxxxxxxxxxxxxx CUDA 全局设置
# 设置 CUDA 运行时库为动态链接
# set(CMAKE_CUDA_RUNTIME_LIBRARY Shared)
set(CMAKE_CUDA_RUNTIME_LIBRARY HYBRID)
include_directories(${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
# cuda 文件单独编译
set(CUDA_SEPARABLE_COMPILATION ON)
set(CUDA_RESOLVE_DEVICE_SYMBOLS ON)


##xxxxxxxxxxxxxxxxxxx 第三方库设置
# fmt::fmt
# 设置FMT_UNICODE=0禁用Unicode支持，避免fmt库中的static_assert错误
# 或者设置为1并确保所有编译器都使用/utf-8选项
add_compile_definitions("FMT_UNICODE=0")

##xxxxxxxxxxxxxxxxxxx MSVC c++ 设置
set(MY_CXX_CMPILE_OPTIONS "")
set(MY_CUDA_CMPILE_OPTIONS "")
if(MSVC)
    message(STATUS ">>>[my] Setting MSVC cl, link")

    # 1. 强制所有 C/C++ 目标使用动态运行时
    # set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
    message(STATUS "[my] MSVC compiler: ${CMAKE_CXX_COMPILER}")
    ##  "/fp:fast"
    set(MY_CXX_CMPL_OPTS_MSVC "/utf-8" "/EHsc" "/Zc:__cplusplus" "/permissive-")
    list(JOIN MY_CXX_CMPL_OPTS_MSVC " " MY_CXX_CMPILE_OPTIONS)
    # message(STATUS "[my] MY_CXX_CMPILE_OPTIONS =>  ${MY_CXX_CMPILE_OPTIONS}")

    list(JOIN MY_CXX_CMPL_OPTS_MSVC "," MY_CUDA_CMPILE_OPTIONS)
    set(MY_CUDA_CMPILE_OPTIONS -Xcompiler="${MY_CUDA_CMPILE_OPTIONS}")
    # message(STATUS "[my] MY_CUDA_CMPILE_OPTIONS => ${MY_CUDA_CMPILE_OPTIONS}")
endif()


# add_compile_options("$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<COMPILE_LANGUAGE:CXX>>:${MY_CXX_CMPILE_OPTIONS}>")
# 可选的：为C++代码禁用特定警告
# add_compile_options("$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<COMPILE_LANGUAGE:CXX>>:/wd4819>")

# get_property(MY_DBG_DIR_COMP_OPTS DIRECTORY ${MY_ROOT_DIR} PROPERTY COMPILE_OPTIONS)
# message(STATUS "[my] MY_DBG_DIR_COMP_OPTS => ${MY_DBG_DIR_COMP_OPTS}")

##xxxxxxxxxxxxxxxxxxx Linux GCC 编译选项
set(MY_COMPILER_ID "${CMAKE_CXX_COMPILER_ID}")
if(NOT CMAKE_CXX_COMPILER_ID)
    set(MY_COMPILER_ID "${CMAKE_C_COMPILER_ID}")
endif()

set(MY_CXX_CMPILE_OPTIONS "")
if(MY_COMPILER_ID STREQUAL "GNU")
    message(STATUS "[my] GNU compiler: ${CMAKE_CXX_COMPILER}")
    # -fvisibility=hidden 默认让符号不可见
    # Set default visibility of all symbols to hidden
    set(CMAKE_CXX_VISIBILITY_PRESET "hidden")
    set(CMAKE_VISIBILITY_INLINES_HIDDEN TRUE)
    ## -Wno-pedantic 禁用pedantic模式下的扩展警告
    ## -Wextra 额外严格警告
    set(MY_CXX_CMPL_OPTS_GCC -finput-charset=utf-8 -fexec-charset=utf-8 -Wall -Wextra -Wno-pedantic)
    list(JOIN MY_CXX_CMPL_OPTS_GCC " " MY_CXX_CMPILE_OPTIONS)

    list(JOIN MY_CXX_CMPL_OPTS_GCC "," MY_CUDA_CMPILE_OPTIONS)
    set(MY_CUDA_CMPILE_OPTIONS "-Xcompiler=${MY_CUDA_CMPILE_OPTIONS}")
    # message(STATUS "[my] MY_CUDA_CMPILE_OPTIONS => ${MY_CUDA_CMPILE_OPTIONS}")
endif()

# 为GCC编译器且为C++代码设置编译选项
# add_compile_options("$<$<AND:$<CXX_COMPILER_ID:GNU>,$<COMPILE_LANGUAGE:CXX>>:${MY_CXX_CMPILE_OPTIONS}>")
#xxxxxxxxxxxxxxxxxxxxxxxxx GPU, nvcc 设置; blackwell
#--------------- nvcc 选项, sync with cl, 但是分隔用 `,` 通过-Xcompiler传递
#add_compile_options("$<$<AND:$<CXX_COMPILER_ID:NVIDIA>,$<COMPILE_LANGUAGE:CUDA>>:${MY_CUDA_CMPILE_OPTIONS}>")

##xxxxxxxxxxxxxxxxxxx 告诉 NVCC 不要狗叫
if(CMAKE_CUDA_COMPILER AND TRUE)
    set(CUDA_WARNING_SUPPRESSIONS
        -diag-suppress=27   # 抑制fmt中的字符值超出范围警告
        -diag-suppress=128  # 抑制fmt中的"loop is not reachable"警告
        -diag-suppress=2417 # 抑制fmt中的constexpr构造函数警告
        -diag-suppress=1388 # 抑制spdlog中的DLL接口规范不一致警告
        -diag-suppress=1394 # 抑制spdlog中的DLL接口字段警告
    )
    list(JOIN CUDA_WARNING_SUPPRESSIONS " " CUDA_WARNING_SUPPRESSIONS)
    set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} ${CUDA_WARNING_SUPPRESSIONS}")
endif()

#================== apply flags
#---- https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS.html
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MY_CXX_CMPILE_OPTIONS}")
message(STATUS "[my] CMAKE_CXX_FLAGS => ${CMAKE_CXX_FLAGS}")
#----
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} ${MY_CUDA_CMPILE_OPTIONS}")
message(STATUS "[nvcc] CMAKE_CUDA_FLAGS => ${CMAKE_CUDA_FLAGS}")